import { EventNames, Props } from "src/types/shape";
import Base from "./Base";
import Scene from "./Scene";

interface TableData {

}

export default class extends Base {
  scene: Scene
  data: TableData[] = []
  linesL: Line[] = []
  linesV: Line[] = []
  moveLine!: Line
  move: boolean = false
  row: number = 10
  column: number = 3
  rowLen: number = 60
  columnLen: number = 30
  constructor(option: Props, scene: Scene) {
    super()
    this.scene = scene
    this.props.width = this.row * this.rowLen
    this.props.height = this.column * this.columnLen
    this.props.x = 350
    this.props.y = 145
    this.moveLine = new Line('level')
    this.init()
  }
  init() {
    const { x, y, width, height } = this.props
    const w = width / this.row
    const h = height / this.column
    const obj: any = {}
    obj.level = {}
    obj.vertical = {}
    for (let i = 0; i < this.row; i++) {
      obj['vertical'][i] = new Line('vertical')
      obj['vertical'][i].index = i
      if (i > 0) {
        obj['vertical'][i - 1].right = obj['vertical'][i]
        obj['vertical'][i].left = obj['vertical'][i - 1]
      }
      obj['vertical'][i].props.height = height
      obj['vertical'][i].props.x = x + i * w
      obj['vertical'][i].props.y = y
      if (i == 0) obj['vertical'][i].isShow = false
      for (let j = 0; j < this.column; j++) {
        const rect = new Rect()
        rect.props.x = obj['vertical'][i].props.x
        rect.props.width = w
        rect.props.height = h

        if (!obj['level'][j]) {
          obj['level'][j] = new Line('level')
          obj['level'][j].index = j
          if (j > 0) {
            obj['level'][j - 1].right = obj['level'][j]
            obj['level'][j].left = obj['level'][j - 1]
          }
          if (j == 0) obj['level'][j].isShow = false
          obj['level'][j].props.x = x
          obj['level'][j].props.height = width
          obj['level'][j].props.y = y + j * h

          rect.props.y = obj['level'][j].props.y

          obj['level'][j].child.push(rect)
        } else {
          rect.props.y = obj['level'][j].props.y
          obj['level'][j].child.push(rect)
        }
        obj['vertical'][i].child.push(rect)
      }
    }
    Object.keys(obj.level).forEach((key) => {
      this.linesL.push(obj.level[key])
    })
    Object.keys(obj.vertical).forEach((key) => {
      this.linesV.push(obj.vertical[key])
    })

    this.handleEvent()
  }
  handleEvent() {
    this.on(EventNames.mouseenter, () => {
      document.body.style.cursor = 'move'
    })
    this.on(EventNames.mouseleave, () => {
      document.body.style.cursor = 'default'
    })
    let activeShape: Line | null = null
    this.linesL.forEach(shape => {
      shape.on(EventNames.mouseenter, () => {
        document.body.style.cursor = 's-resize'
      })
      shape.on(EventNames.mouseleave, () => {
        document.body.style.cursor = 'default'
      })
      shape.on(EventNames.mousedown, () => {
        this.moveLine.init(shape)
        this.move = true
        activeShape = shape
      })
      this.scene.IDS.add(shape.getRgbaId())
      this.scene.eventSimulator.addListeners(shape.getRgbaId(), shape.getListeners())
      shape.child.forEach(item => {
        this.scene.IDS.add(item.getRgbaId())
        this.scene.eventSimulator.addListeners(item.getRgbaId(), item.getListeners())
      })
    })
    this.linesV.forEach(shape => {
      shape.on(EventNames.mouseenter, () => {
        document.body.style.cursor = 'e-resize'
      })
      shape.on(EventNames.mouseleave, () => {
        document.body.style.cursor = 'default'
      })
      shape.on(EventNames.mousedown, () => {
        this.moveLine.init(shape)
        this.move = true
        activeShape = shape
      })
      this.scene.IDS.add(shape.getRgbaId())
      this.scene.eventSimulator.addListeners(shape.getRgbaId(), shape.getListeners())
      shape.child.forEach(item => {
        this.scene.IDS.add(item.getRgbaId())
        this.scene.eventSimulator.addListeners(item.getRgbaId(), item.getListeners())
      })
    })
    document.addEventListener(EventNames.mousemove, (event: MouseEvent) => {
      if (!activeShape) return
      const rect = this.scene.domElement.getBoundingClientRect()

      const { props, left, right, lineType } = this.moveLine

      const dx = event.clientX - rect.left
      const dy = event.clientY - rect.top
      const disx = (props.x + (dx - (props.x - this.props.width / 2)) - this.props.lateX)
      const disy = (props.y + (dy - (props.y - this.props.height / 2)) - this.props.lateY)

      if (lineType == 'level') {
        document.body.style.cursor = 's-resize'
        if (right) {
          if (disy < left.props.y) {
            props.y = left.props.y
          } else if (disy > right.props.y) {
            props.y = right.props.y
          } else {
            props.y = disy
          }
        } else {
          if (disy < left.props.y) {
            props.y = left.props.y
          }
          else if (disy > this.props.y + this.props.height + this.props.lateY) {
            props.y = this.props.y + this.props.height + this.props.lateY
          }
          else {
            props.y = disy
          }
        }
      } else {
        document.body.style.cursor = 'e-resize'
        if (right) {
          if (disx < left.props.x) {
            props.x = left.props.x
          } else if (disx > right.props.x) {
            props.x = right.props.x
          } else {
            props.x = disx
          }
        } else {
          if (disx < left.props.x) {
            props.x = left.props.x
          }
          else if (disx > this.props.x + this.props.height + this.props.lateX) {
            props.x = this.props.x + this.props.height + this.props.lateX
          }
          else {
            props.x = disx
          }
        }
      }
    })
    document.addEventListener(EventNames.mouseup, () => {
      if (!activeShape) return
      this.move = false
      activeShape.setProps({ ...this.moveLine.props, borderColor: 'black' })

      const { props, left, right, lineType } = activeShape

      if (lineType == 'level') {
        const leftH = props.y - left.props.y
        const rightH = (right ? right.props.y : this.props.y + this.props.height) - props.y
        left.child.forEach(shape => {
          shape.props.height = leftH
          shape.props.y = left.props.y
        })
        activeShape.child.forEach(shape => {
          shape.props.height = rightH
          shape.props.y = props.y
        })
      } else {
        const leftH = props.x - left.props.x
        const rightH = (right ? right.props.x : this.props.x + this.props.width) - props.x
        left.child.forEach(shape => {
          shape.props.width = leftH
          shape.props.x = left.props.x
        })
        activeShape.child.forEach(shape => {
          shape.props.width = rightH
          shape.props.x = props.x
        })
      }
      activeShape = null
    })
  }
  draw(ctx: CanvasRenderingContext2D, osCtx: OffscreenCanvasRenderingContext2D): void {
    const { x, y, width, height } = this.props

    ctx.save()
    this.transform(ctx)
    this.initOptions(ctx, 1)
    ctx.roundRect(x, y, width, height, 6)
    ctx.clip()
    this.linesL.forEach(line => {
      line.child.forEach(rect => {
        rect.draw(ctx, osCtx)
      })
    })
    this.linesV.forEach(line => {
      line.child.forEach(rect => {
        rect.draw(ctx, osCtx)
      })
    })
    this.linesL.forEach(line => {
      if (line.isShow)
        line.draw(ctx, osCtx)
    })
    this.linesV.forEach(line => {
      if (line.isShow)
        line.draw(ctx, osCtx)
    })
    ctx.roundRect(x, y, width, height, 6)
    ctx.stroke()
    if (this.move) {
      ctx.beginPath()
      ctx.fillStyle = 'rgba(255,255,255,0.2)'
      ctx.rect(x, y, width, height)
      ctx.fill()
      ctx.closePath()
      this.moveLine && this.moveLine.draw(ctx, osCtx)
    }
    ctx.restore()

    // 镜像画布
    osCtx.save()

    this.transform(osCtx)

    osCtx.restore()
    // 镜像画布
    osCtx.save()

    this.transform(osCtx)
    osCtx.beginPath()
    this.initOptions(osCtx, 2)
    osCtx.rect(x, y, width, height)
    osCtx.fill()
    osCtx.stroke()
    osCtx.closePath()
    this.linesL.forEach(line => {
      line.child.forEach(rect => {
        rect.drawMirror(osCtx)
      })
    })
    this.linesV.forEach(line => {
      line.child.forEach(rect => {
        rect.drawMirror(osCtx)
      })
    })
    this.linesL.forEach(line => {
      if (line.isShow)
        line.drawMirror(osCtx)
    })
    this.linesV.forEach(line => {
      if (line.isShow)
        line.drawMirror(osCtx)
    })
    osCtx.lineWidth = 10
    osCtx.strokeRect(x, y, width, height)

    osCtx.restore()
  }
}

class Line extends Base {
  lineType: 'level' | 'vertical' = 'level'
  child: any[] = []
  isShow: boolean = true
  left!: Line
  right!: Line
  index: number = 0
  constructor(type: 'level' | 'vertical') {
    super()
    this.lineType = type
    this.props.width = 2
    this.props.height = 150
  }
  init(shape: Line) {
    this.isShow = true
    this.lineType = shape.lineType
    this.setProps(shape.props)
    this.right = shape.right
    this.left = shape.left
    this.props.borderColor = 'yellow'
  }
  draw(ctx: CanvasRenderingContext2D, osCtx: OffscreenCanvasRenderingContext2D): void {
    const { x, y, height } = this.props
    ctx.save()

    ctx.beginPath()
    this.initOptions(ctx, 1)
    ctx.moveTo(x, y)
    if (this.lineType == 'level') {
      ctx.lineTo(x + height, y)
    } else {
      ctx.lineTo(x, y + height)
    }

    ctx.stroke()
    ctx.closePath()

    ctx.restore()

  }
  drawMirror(osCtx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D): void {
    const { x, y, width, height } = this.props
    // 镜像画布
    osCtx.save()

    osCtx.beginPath()
    this.initOptions(osCtx, 2)
    osCtx.lineWidth = width + 10
    if (this.lineType == 'level') {
      osCtx.rect(x, y, height, width)
    } else {
      osCtx.rect(x, y, width, height)
    }
    osCtx.stroke()

    osCtx.restore()
  }
}
class Rect extends Base {
  child: any[] = []
  constructor() {
    super()
    this.props.width = 20
    this.props.height = 150
    this.props.bgcolor = '#ffffff'
    this.props.text = '妙手空空\n妙手回春'
    this.props.textObj = this.props.text.split('\n')
  }
  draw(ctx: CanvasRenderingContext2D, osCtx: OffscreenCanvasRenderingContext2D): void {
    const { x, y, width, height, textObj, textColor } = this.props

    ctx.save()

    ctx.beginPath()
    this.initOptions(ctx, 1)
    ctx.rect(x, y, width, height)

    ctx.fill()
    ctx.textBaseline = 'top'
    ctx.fillStyle = textColor
    const { actualBoundingBoxAscent, actualBoundingBoxDescent } = ctx.measureText('妙')
    textObj.forEach((text, i) => {
      ctx.fillText(text, x + 3, y + i * (actualBoundingBoxAscent + actualBoundingBoxDescent) + 3, width - 6)
    })

    ctx.closePath()

    ctx.restore()
  }
  drawMirror(osCtx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D): void {
    const { x, y, width, height } = this.props

    osCtx.save()
    osCtx.beginPath()
    this.initOptions(osCtx, 2)
    osCtx.rect(x, y, width, height)
    osCtx.fill()
    osCtx.stroke()
    osCtx.closePath()

    osCtx.restore()
  }
  //rgb颜色随机
  rgb() {
    const r = Math.floor(Math.random() * 256);
    const g = Math.floor(Math.random() * 256);
    const b = Math.floor(Math.random() * 256);
    return `rgb(${r},${g},${b})`;
  }
}